home *** CD-ROM | disk | FTP | other *** search
- comment |
-
- This program unravels DOS's (on most machines, Versions 2.0 up to 3.3)
- memory control blocks (MCBs) and prints the information it finds.
- If run under DOS 3.0 or later, it will also print the name it can
- find for each program in memory. The commenting and wording of
- printing messages have been changed in a number of places.
-
- DOS allocates blocks in 16-byte paragraphs, so shift the Block size
- reported by the program 4 bits left (multiply by 16!) to determine
- the actual block length in bytes.
-
- Microsoft has never officially documented how MSDOS allocates memory,
- so much of this program is based on techniques others have discovered.
-
- MCB format:
-
- Byte Offset Description
- -----------------------------------------------------------------------
-
- 0 contains byte 'M' if other MCBs higher
- in memory, 'Z' if highest current MCB.
-
- 1 - 2 PID of block owner (identical to seg
- addr of the program's program segment
- prefix [PSP]).
-
- 3 - 4 length of block in 16-byte paragraphs.
-
-
- Written for MASM 5.0 by Hardin Brothers for PCResource. The original
- appeared in the July 1988 issue of their magazine. Entire contents of
- the July 1988 issue (C) Copyright 1988 by
- IDG Communications/Peterborough, Inc.
-
- Hardin Brothers is a freelance programmer and technical writer. Write
- to him at 280 N. Campus Ave., Upland, CA 91786. Enclose a self-
- addressed, stamped envelope for a reply.
-
- |
-
- LF equ 0Ah ; linefeed char
- CR equ 0Dh ; carriage return char
- STDOUT equ 1 ; standard output device
-
- PRINT macro text
- mov AH, 40h ; INT 21h service 40h: write to device/file
- mov BX, STDOUT ; send message to std output
- lea DX, &text&msg ; DS:DX gets address of message string Xmsg
- mov CX, &text&len ; get length of message
- int 21h ; call DOS service
- endm
-
- EXIT macro val
- mov AH, 4Ch ; INT 21h service 4Ch: exit from program
- ; also returns a value. replaces old INT 20h.
- mov AL, val ; return value byte
- int 21h
- endm
-
- .MODEL SMALL
- .STACK
- .DATA
- ourpid dw ?
- maxmem dw ?
- basepsp dw ?
- DosVer dw ?
- DosV3 db 0
-
- NoV1msg db 'This program cannot be used with DOS Ver. 1.x', CR, LF
- NoV1len equ $-NoV1msg
-
- VERmsg db 'Unknown DOS version -- cannot find head of memory'
- db ' chain.', CR, LF
- VERlen equ $-VERmsg
-
- LERRmsg db "There apparently in an error with this program's"
- db ' MCB.', CR, LF
- LERRlen equ $-LERRmsg
-
- ERRmsg db 'Memory allocation error -- Illegal MCB found.', CR, LF
- ERRlen equ $-ERRmsg
-
- HDRmsg db CR, LF, CR, LF
- db ' MCB Block Block Block Block'
- db ' Process', CR, LF
- db ' Seg Seg Owner Size Type '
- db ' Name ', CR, LF
- db ' --------------------------------------------'
- db '------------', CR, LF
- HDRlen equ $-HDRmsg
-
- mcbmsg db ' '
- mcbadr db '0000 '
- blkadr db '0000 '
- blkown db '0000 '
- blksiz db '0000 '
- mcblen equ $-mcbmsg
-
- CRLFmsg db CR, LF
- CRLFlen equ $-CRLFmsg
-
- PRGmsg db 'Prog '
- PRGlen equ $-PRGmsg
-
- ENVmsg db 'Envr '
- ENVlen equ $-ENVmsg
-
- OTHmsg db 'Data? '
- OTHlen equ $-OTHmsg
-
- hexlist db '0123456789ABCDEF'
-
- memMSG db CR, LF, CR, LF
- db 'Top of memory: '
- memSIZ db '0000h.', CR, LF
- db 'Next program will load at: '
- memLOC db '0000h.', CR, LF, CR, LF
- db 'Memory available: '
- memAVL db '00000h bytes.', CR, LF, CR, LF
- memlen equ $-memMSG
-
- .CODE
- start: cld
- mov AX, @data
- mov DS, AX ; set DS to "our" data seg
- mov AH, 30h ; INT 21h service 30h: Get DOS Version
- int 21h
- mov DosVer, AX ; save entire version number
- cmp al, 2 ; at least DOS version 2.x ?
- jae verOK ; if so, continue...
- PRINT NoV1 ; else complain about it
- EXIT -1 ; and quit
-
- verOK: sub AL, 2 ; test for version 3.x
- mov DosV3, AL ; save result (0 or >0) as a flag
-
- mov BX, 2 ; addr PSP:2 contains maxmem
- mov AX, ES:[BX]
- mov maxmem, AX
- push ES
- mov AX, ES ; get addr of "our" PSP
- mov ourpid, AX ; save PSP
- dec AX ; point to "our" MCB
- mov ES, AX ; ES now points to our MCB
- mov BX, 1 ; offset of PID in our MCB
- inc AX ; AX contains our PID again
-
- cmp AX, word ptr ES:[BX]
- jz okay ; if not both the same, something's wrong!
- PRINT LERR
- EXIT -1
-
- okay: pop ES ; ES points to our PSP
- call findStart ; get head of memory chain
-
- ;----------------
- ; ES now points to the PSP in lowest memory, which ordinarily belongs
- ; to the first and only copy of COMMAND.COM. This PSP will be used as
- ; the place to begin the trek through memory.
- ;----------------
-
- PRINT HDR ; output table column headers
- rB1: push ES ; save ES
- call printMCB ; print memory block info
- mov AX, ES ; put MCB seg in AX
- inc AX ; AX contains block seg
- mov ES, AX ; ES points to memory block
- call printTYPE ; print block type
- jc rB2 ; skip to rB2 if type not ENVR
- test DosV3, -1 ; using Version 3.x or later?
- jz rB2 ; skip to rB2 if not
- call printCMD ; print program name if found
-
- rB2: PRINT CRLF ; terminate output line
- pop ES ; ES points to current MCB
- mov BX, 0 ; addr ES:BX points to block type (M or Z)
-
- cmp byte ptr ES:[BX], 'Z' ; at tail of memory chain?
- jz rB3 ; skip to rB3 if at tail
- mov AX, ES ; get current MCB seg
- inc AX ; AX contians block seg
- mov BX, 3 ; addr ES:BX points to block size
- add AX, ES:[BX] ; addr block size
- mov ES, AX ; ES points to next MCB
- jmp rB1 ; traverse chain. loop back.
-
- rB3: call printMEM ; print memory info
- EXIT 0 ; and terminate program
-
- ;----------------
- ; Find the head of the MCB list.
- ; This is the trickiest part of the program, as it is rarely
- ; documented. Method used was created by Ted Mirecki, and was published
- ; in the October 1987 issue of PC Tech Journal.
- ;----------------
-
- findStart proc near
- mov AX, 0 ; start with seg 0
- mov ES, AX ; in ES
- mov BX, 0C3h ; find seg of resident DOS
- mov AX, ES:[BX] ; put the seg in AX
- mov ES, AX ; ES points to resident DOS seg
- mov AX, DosVer ; get DOS Version
- xchg AH, AL ; Ver major in AH, minor in AL
- mov BX, 10Ah ; offset for Ver 2.0
- cmp AX, 0209h ; is this Ver 2.00 - 2.09 ?
- jbe fS2 ; skip to fS2 if so
- mov BX, 0F6h ; offset for Ver 2.1
- cmp AX, 0213h ; is this Ver 2.10 - 2.19 ?
- jbe fS2 ; skip to fS2 if so
- cmp AL, 2 ; is this some unknown Ver 2.x ?
- jne fS1 ; skip to fS1 if not
- PRINT VER
- EXIT -1
-
- fS1: mov BX, 128h ; offset for Ver 3.0
- cmp AX, 0309h ; is this Ver 3.00 - 3.09 ?
- jbe fS2 ; skip to fS2 if so
- mov BX, 22h ; offset for Ver 3.10 - 3.30
-
- fS2: les BX, ES:[BX] ; get head of memory chain
- ret
- findStart endp
-
- comment |
- ;----------------
- ; This is an alternate method of finding the head of the MCB list.
- ; This method will trace backwards to the last copy of COMMAND.COM
- ; installed in memory, and should work if the preceding method does
- ; not with your version of MSDOS.
- ;----------------
-
- findStart proc near
- mov BX, 16h ; addr PSP:16h points to parental PSP
- fS1: mov AX, ES:[BX] ; get addr of parental PSP
- cmp AX, 0 ; at tail of chain ? (1st test)
- jz fS2 ; skip to fS2 if so
- cmp AX, basepsp ; at tail of chain ? (2nd test)
- jz fS2 ; skip to fS2 if so
- mov basepsp, AX ; if not, save this value
- mov ES, AX ; ES points to parental PSP
- jmp fS1 ; loop back. traverse chain.
-
- fS2: mov AX, ES ; get current PSP seg
- dec AX ; AX is seg of MCB
- mov ES, AX ; ES points to head of memory chain (1st MCB)
- ret
- findStart endp
- |
-
- ;----------------
- ; ES points to a MCB. Print the information contained in the MCB.
- ;----------------
-
- printMCB proc near
- mov AX, ES ; AX is seg of MCB
- lea DI, mcbadr ; DI points to message area
- call hextoasc ; convert AX to ASCII
- inc AX ; AX is block addr
- lea DI, blkadr
- call hextoasc
- mov BX, 0 ; is this really a block ?
- mov AL, ES:[BX] ; get first byte
- cmp AL, 'M' ; part of chain ?
- je pM1 ; skip to pM1 if so
- cmp AL, 'Z' ; tail of chain ?
- je pM1 ; skip to pM1 if so
- PRINT ERR ; else notify error
- EXIT -1 ; and terminate program
-
- pM1: mov BX, 1 ; addr ES:BX points to block PID
- mov AX, ES:[BX] ; get block PID
- lea DI, blkown
- call hextoasc
- mov BX, 3 ; addr ES:BX points to block size
- mov AX, ES:[BX] ; get block size
- lea DI, blksiz
- call hextoasc
- PRINT mcb
- ret
- printMCB endp
-
- ;----------------
- ; ES points to a memory block. Determine if it is a PSP, ENVR, or
- ; unknown block. Note that the test for a PSP block checks if the
- ; first 4 bytes of the block are ASCII, so a data block could con-
- ; ceivably show up as a PSP.
- ;----------------
-
- printTYPE proc near
- mov BX, 0 ; addr ES:BX points to head of block
-
- cmp byte ptr ES:[BX], 0CDh ; a PSP always starts at CDh
- jnz typ1 ; no PSP here, skip to typ1
- PRINT PRG
- stc ; set carry flag
- ret
-
- typ1: mov CX, 4 ; test count of 4 chars
- typ2: mov AL, ES:[BX] ; get a byte
- cmp AL, ' ' ; check for CTRL code
- jb typ3 ; skip to typ3 if so
- cmp AL, 'a' ; check lowercase
- jae typ3 ; skip to typ3 if so
- inc BX ; otherwise point to next byte
- loop typ2 ; and continue
- PRINT ENV ; must be ENVR block type
- clc ; clear carry flag
- ret
-
- typ3: PRINT OTH ; unknown block type
- stc ; set carry flag
- ret
- printTYPE endp
-
- ;----------------
- ; ES points to an environment segment. Scan the segment and print the
- ; name of the program reported to own this environment. The procedure
- ; will only work with DOS Ver 3.0 and later.
- ;----------------
-
- printCMD proc near
- push DS ; save data seg
- push ES ; copy ES
- pop DS ; to DS
- mov SI, 0 ; addr DS:SI points to environ text
- mov CX, 8000h ; max. size of environ = 32768 bytes
- mov AX, 0 ; init AX for search
-
- pC1: lodsb ; get byte in AL, incr SI
- or AX, AX ; set flags. test AX.
- jz pC2 ; AX empty, found start of CMD
- mov AH, AL ; AX not empty, save byte
- loop pC1 ; and get next byte
-
- pC1a: pop DS ; nothing found. restore DS
- ret
-
- pC2: lodsw ; get next word in AX, incr SI
- cmp AX, 1 ; ought to be 0001h
- jne pC1a ; skip to pC1a if not
- mov DX, SI ; save start addr
- mov CX, 0 ; ready byte count
-
- pC3: lodsb ; get next byte, incr SI
- inc CX ; incr byte count
- cmp AL, ' ' ; end of string?
- ja pC3 ; loop if not
- mov BX, STDOUT ; get ready to print
- mov AH, 40h ; INT 21h service 40h: write to file/device
- int 21h
- pop DS ; restore DS
- ret
- printCMD endp
-
- ;----------------
- ; Print memory block information.
- ;----------------
-
- printMEM proc near
- mov AX, maxmem
- lea DI, memSIZ
- call hextoasc
- mov AX, ourpid
- lea DI, memLOC
- call hextoasc
- mov AX, maxmem
- sub AX, ourpid
- lea DI, memAVL
- call hextoasc
- PRINT mem
- ret
- printMEM endp
-
- ;----------------
- ; Put value in AX as ASCII-Hex into location at addr DS:DI
- ; Note: procedure can only alter DI
- ;----------------
-
- hextoasc proc near
- push AX
- push BX
- push CX ; Save registers
- push ES ; Save ES
- push DS ; Copy DS
- pop ES ; to ES
- lea BX, hexlist ; addr DS:BX points to list of hex chars
- xchg AH, AL ; swap bytes
- call hexbyte ; process one byte
- xchg AH, AL ; swap bytes back
- call hexbyte ; process other byte
- pop ES ; Restore ES
- pop CX
- pop BX
- pop AX ; Restore registers
- ret
-
- hexbyte proc near
- push AX ; save AL
- and AL, 0F0h ; mask low nibble
- mov CL, 4 ; bit shift count
- shr AL, CL ; move high nibble down
- xlat ; translate nibble to ASCII char
- stosb ; store char at addr ES:DI, incr DI
- pop AX ; restore AL
- push AX ; save AX once more
- and AL, 00Fh ; mask high nibble
- xlat ; translate to ASCII
- stosb ; store char in string
- pop AX ; restore AX
- ret
- hexbyte endp
- hextoasc endp
-
- end start
-